#include "C_SQLiteSpaceObject.h"
#include "C_SpaceStar.h"
#include "C_SpaceObjectFactory.h"

C_SQLiteSpaceObject::C_SQLiteSpaceObject(std::string path) : m_readyGen(true)
{
	m_sql = new C_SQLite();
	C_SQLiteTable tbl(m_sql);
	tbl.setName("space_objects");
	tbl.add("x INTEGER NOT NULL");
	tbl.add("y INTEGER NOT NULL");
	tbl.add("fx INTEGER NOT NULL");
	tbl.add("fy INTEGER NOT NULL");
	tbl.add("type INTEGER NOT NULL");
	tbl.add("data TEXT NOT NULL");

	m_sql->createIfNotExist(path, &tbl);
}


C_SQLiteSpaceObject::~C_SQLiteSpaceObject()
{
}

void C_SQLiteSpaceObject::add(E_SpaceObject type, int x, int y, int fx, int fy, std::string data)
{
	C_SQLiteInsert in(m_sql);
	in.toTable("space_objects");
	in.add("x", std::to_string(x));
	in.add("y", std::to_string(y));
	in.add("fx", std::to_string(fx));
	in.add("fy", std::to_string(fy));
	in.add("type", std::to_string(type));
	in.add("data", "'" + data + "'");
	in.exec();
}

void C_SQLiteSpaceObject::loadFromJSON(std::string str, C_SpaceStar *star)
{
	json_t			*rootJSON;
	json_error_t	errorJSON;

	rootJSON = json_loads(str.c_str(), 0, &errorJSON);

	//test
	EX_R(!rootJSON, "[JSON]:" + std::to_string(errorJSON.line) + errorJSON.text);

	S_JSON_Star starj;

	starj.name = json_object_get(rootJSON, "name");				EX_R(!json_is_string(starj.name), "[JSON]: Star 'Name' cannot load!");
	starj.type = json_object_get(rootJSON, "type");				EX_R(!json_is_string(starj.type), "[JSON]: Star 'Type' cannot load!");
	starj.spectral = json_object_get(rootJSON, "spectral");		EX_R(!json_is_string(starj.spectral), "[JSON]: Star 'spectral' cannot load!");
	starj.effTemp = json_object_get(rootJSON, "effTemp");		EX_R(!json_is_number(starj.effTemp), "[JSON]: Star 'effTemp' cannot load!");
	starj.mass = json_object_get(rootJSON, "mass");				EX_R(!json_is_real(starj.mass), "[JSON]: Star 'mass' cannot load!");
	starj.radius = json_object_get(rootJSON, "rasius");			EX_R(!json_is_real(starj.radius), "[JSON]: Star 'radius' cannot load!");
	starj.luminosity = json_object_get(rootJSON, "luminosity"); EX_R(!json_is_real(starj.luminosity), "[JSON]: Star 'luminosity' cannot load!");
	starj.integrity = json_object_get(rootJSON, "integrity");	EX_R(!json_is_real(starj.integrity), "[JSON]: Star 'integrity' cannot load!");
	starj.elements = json_object_get(rootJSON, "elements");		EX_R(!json_is_array(starj.elements), "[JSON]: Star 'elements' cannot load!");

	for (int i = 0; i < json_array_size(starj.elements); i++)
	{
		json_t* elem = json_array_get(starj.elements, i);
		json_t* id = json_object_get(elem, "id"); EX_R(!json_is_number(id), "[JSON]: Star element id cannot load!");
		json_t* pc = json_object_get(elem, "pc"); EX_R(!json_is_real(pc), "[JSON]: Star element pc cannot load!");
		star->addElem(json_real_value(pc), GET_ELEM_BY_ID(json_number_value(id)));
	}

	std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
	std::wstring name = converter.from_bytes(std::string(json_string_value(starj.name)));
	star->setName(name);
	star->setTypeFromString(json_string_value(starj.spectral));
	star->setEffTemp(json_number_value(starj.effTemp));
	star->setMass(json_real_value(starj.mass));
	star->setRadius(json_real_value(starj.radius));
	star->setLuminosity(json_real_value(starj.luminosity));
	star->setIntegrity(json_real_value(starj.integrity));

	json_decref(rootJSON);
}

void C_SQLiteSpaceObject::loadSpaceObjects(S_Rangei x, S_Rangei y)
{
	m_readyGen = false;

	WR("START OBJECT")
	C_SQLiteSelect sel(m_sql);
	sel.setTable("space_objects");
	sel.setColumns("*");
	sel.setWhere("x >= " + std::to_string(x.min) + " AND x <= " + std::to_string(x.max) +
		" AND y >= " + std::to_string(y.min) + " AND y <= " + std::to_string(y.max));

	WR(sel.execToStr());

	sqlite3_stmt *statement;

	m_sql->execStmt(sel.execToStr(), statement);

	int res = 0;

	/*int ctotal = sqlite3_column_count(statement);*/
	//while (1)
	//{
	//	res = sqlite3_step(statement);

	//	if (res == SQLITE_ROW)
	//	{
	//		for (int i = 0; i < ctotal; i++)
	//		{
	//			std::string str = (char*)sqlite3_column_text(statement, i);
	//			WR(str);
	//		}
	//	}

	//	if (res == SQLITE_DONE || res == SQLITE_ERROR)
	//	{
	//		break;
	//	}
	//}

	while (1)
	{
		res = sqlite3_step(statement);

		if (res == SQLITE_ROW)
		{
				C_SpaceStar *star = new C_SpaceStar(m_map);
				int x = boost::lexical_cast<int>(sqlite3_column_text(statement, 0));
				int y = boost::lexical_cast<int>(sqlite3_column_text(statement, 1));
				int fx = boost::lexical_cast<int>(sqlite3_column_text(statement, 2));
				int fy = boost::lexical_cast<int>(sqlite3_column_text(statement, 3));
				int type = boost::lexical_cast<int>(sqlite3_column_text(statement, 4));
				std::string jsonStr = (char*)sqlite3_column_text(statement, 5);
				star->setSpacePos(x, y);
				star->setPos(fx, fy);
				this->loadFromJSON(jsonStr, star);
				star->compose();
				m_map->addObject(star);
				m_factory->add(star);
		}

		if (res == SQLITE_DONE || res == SQLITE_ERROR)
		{
			break;
		}
	}

	WR("END OBJECT")
	m_readyGen = true;
}